package main

import (
	"config"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/satori/go.uuid"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"time"
)

var (
	httpClient = &http.Client{
		Timeout: 3 * time.Second,
	}
)

/**
 *
 * @return
 */
func api_file_upload(c *gin.Context) {
	// token := c.Request.Header.Get("token")
	// token = strings.Trim(token, " ")

	// 读取配置文件
	cate := c.Param("cate")
	orz, ok := config.Get(&cate)
	if !ok {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "请求失败",
			},
		})
		return
	}

	if 1 > orz.Limits.Files {
		upload(c, &cate, &orz)
		return
	}

	uploads(c, &cate, &orz)
}

type Good struct {
	Id       string `json:"id"`
	Original string `json:"original"`
	Extname  string `json:"extname"`
	Size     int64  `json:"size"`
}

type Goods []Good

/**
 * 单文件覆盖
 *
 * @return
 */
func upload(c *gin.Context, cate *string, orz *config.Orz) {
	file, err := c.FormFile("file")
	if nil != err {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "请选择文件",
			},
		})
		return
	}

	if file.Size > orz.Limits.FileSize {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "文件大小超出限制",
			},
		})
		return
	}

	// 文件扩展名
	extname := getExtname(&file.Filename)
	if ok := isExists(&orz.Extname, &extname); !ok {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "不支持的文件格式",
			},
		})
		return
	}

	// 用户标识
	user, ok := getRemoteUser(&c.Request.URL.RawQuery)
	if !ok {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "验证失败",
			},
		})
		return
	}

	user_id := user["user_id"].(string)

	if err := c.SaveUploadedFile(file, path.Join(*ROOT_PATH, *cate, (user_id+extname))); nil != err {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "保存失败",
			},
		})
		return
	}

	good := Good{
		Id:       user_id,
		Original: file.Filename,
		Extname:  extname,
		Size:     file.Size,
	}

	var goods Goods
	goods = append(goods, good)

	c.JSON(http.StatusOK, gin.H{
		"user_id": user_id,
		"date":    time.Now().Format("20060102"),
		"list":    goods,
	})
}

/**
 * 批量上传
 *
 * @return
 */
func uploads(c *gin.Context, cate *string, orz *config.Orz) {
	// keywords := c.Request.Header.Get("keywords")
	form, err := c.MultipartForm()
	if nil != err {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "请选择文件",
			},
		})
		return
	}

	files := form.File["file"]

	if len(files) > orz.Limits.Files {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "文件数量超出限制",
			},
		})
		return
	}

	// 用户标识
	user, ok := getRemoteUser(&c.Request.URL.RawQuery)
	if !ok {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "验证失败",
			},
		})
		return
	}

	user_id := user["user_id"].(string)

	// 年月日
	folder1 := time.Now().Format("20060102")

	// 根目录/分类/年月日/用户标识
	if err := os.MkdirAll(path.Join(*ROOT_PATH, *cate, folder1, user_id), os.ModePerm); nil != err {
		c.JSON(http.StatusOK, gin.H{
			"error": gin.H{
				"msg": "创建目录失败",
			},
		})
		return
	}

	var goods Goods

	for _, file := range files {
		if file.Size > orz.Limits.FileSize {
			break
		}

		// 文件扩展名
		extname := getExtname(&file.Filename)
		if ok := isExists(&orz.Extname, &extname); !ok {
			break
		}

		u1 := strings.Replace(uuid.NewV1().String(), "-", "", -1)

		if err := c.SaveUploadedFile(file, path.Join(*ROOT_PATH, *cate, folder1, user_id, (u1+extname))); nil != err {
			break
		}

		good := Good{
			Id:       u1,
			Original: file.Filename,
			Extname:  extname,
			Size:     file.Size,
		}

		goods = append(goods, good)
	}

	c.JSON(http.StatusOK, gin.H{
		"user_id": user_id,
		"date":    folder1,
		"list":    goods,
	})
}

/**
 *
 * @return
 */
func getRemoteUser(rawQuery *string) (map[string]interface{}, bool) {
	resp, err := httpClient.Get(*AUTH_SERV + *rawQuery)
	if nil != err {
		return nil, false // 验证服务不可用
	}
	defer resp.Body.Close()

	if http.StatusOK != resp.StatusCode {
		return nil, false
	}

	body, err := ioutil.ReadAll(resp.Body)
	if nil != err {
		return nil, false // 验证信息读取失败
	}

	var msg map[string]interface{}
	if err := json.Unmarshal(body, &msg); nil != err {
		return nil, false // 非法格式
	}

	if err := msg["error"]; nil != err {
		return nil, false
	}

	return msg, true
}

/**
 * 判断文件格式
 *
 * @return
 */
func isExists(extnames *[]string, extname *string) bool {
	for i := 0; i < len(*extnames); i++ {
		if (*extnames)[i] == (*extname) {
			return true
		}
	}
	return false
}

/**
 * 文件扩展名
 *
 * @return
 */
func getExtname(name *string) string {
	return strings.ToLower(path.Ext(*name))
}
